export function cloneObject(obj:any) {
    // Handle the 3 simple types, and null or undefined
    if (null === obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
      const copy = new Date();
      copy.setTime(obj.getTime());
      return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
      var newObj:any = [];
      for (let i = 0, len = obj.length; i < len; ++i) {
        newObj[i] = cloneObject(obj[i]);
      }
      return newObj;
    }

    // Handle Object
    if (obj instanceof Object) {
      var newObj:any = {};
      for (const attr in obj) {
        if (obj.hasOwnProperty(attr)) {
          const value = cloneObject(obj[attr]);
          if (value != null && JSON.stringify(value) != "{}") {
            if (typeof(value)=="string" && value.trim()!= "") newObj[attr] = value;
            if (typeof(value)!="string") newObj[attr]=value;
          }
        }
      }
      return newObj;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
};

export function guid() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
      const r = Math.random() * 16 | 0,
          v = c == 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
  });
};

export function parseContent(sourceContent:string) {
    function replacer(key:string, value:any) {
        if (typeof value === 'function' && key!="dispose") {
            return value.toString();
        }
        return value;
    }
    const content = JSON.parse(JSON.stringify(sourceContent, replacer));
    return content;
};

export function converFunction(option:any, merge:boolean) {
  if (!(window as any).baskreport) {
    (window as any).baskreport = {chartOptions:[]};
  }
  const baskreport = (window as any).baskreport;
  if (!baskreport.chartOptions) {
    baskreport.chartOptions = {};
  }
  if (baskreport.chartOptions[option.key] && merge) {
    Object.assign(baskreport.chartOptions[option.key], option)
  } else {
    baskreport.chartOptions[option.key]= option;
  }
  if (!baskreport.format) {
    baskreport.format = {};
  }
  if (!baskreport.format.formatDate) {
    baskreport.format.formatDate = function formatDate(date:Date,pattern:any) {
      let ret;
      const opt:any = {
          "y+": date.getFullYear().toString(),        // 年
          "M+": (date.getMonth() + 1).toString(),     // 月
          "d+": date.getDate().toString(),            // 日
          "H+": date.getHours().toString(),           // 时
          "m+": date.getMinutes().toString(),         // 分
          "s+": date.getSeconds().toString(),          // 秒
          "S+": date.getMilliseconds().toString()          // 毫秒
      };
      for (const k in opt) {
          ret = new RegExp("(" + k + ")").exec(pattern);
          if (ret) {
              pattern = pattern.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
          };
      };
      return pattern;
    }
  }
  if (!baskreport.format.getFormatterString) {
    baskreport.format.getFormatterString = function getFormatterString (variable:any, paramValue:string){
      let value = '';
      if (variable.formatter) {
        const fmt = variable.formatter;
        const formatType = fmt.formatType;
        if (formatType=='text') {
          value += paramValue;
        } else if (formatType=='number') {
          value += "numeral("+paramValue+").format('"+fmt.formatPattern+"')";
        } else if (formatType=='date') {
          value += "window.baskreport.format.formatDate(new Date('"+paramValue+"'),'"+fmt.formatPattern+"')";
        } else if (formatType=='currency') {
          value += "numeral("+paramValue+").format('"+fmt.formatPattern+"')";
        }  else if (formatType=='percent') {
          value += "numeral("+paramValue+"/100).format('"+fmt.formatPattern+"')";
        } else {
          value += paramValue;
        }
      } else {
        value += paramValue;
      }
      return value;
    }
  }
    // Handle Object
    if (option instanceof Object) {
        for (const attr in option) {
            if (option.hasOwnProperty(attr)) converOptionFunctions(option.key, attr, option[attr]);
        }
    }
};



function genFormatterFunction(optionKey:string, itemData:any){
  let value = '';
  let seriesNameValue = 'let seriesNamevalue = \'\';';
  let nameValue = 'let namevalue = \'\';';
  let percentValue = 'let percentvalue = \'\';';
  let keyValue = 'let keyvalue = \'\';';
  let params = 'params';
  if (itemData.parameterNames) {
    const names = itemData.parameterNames.split(",");
    params = names[0];
  }
  itemData.templateVariables.forEach((variable:any)=>{
      if (variable.value) {
          if (variable.name=="seriesName") {
            seriesNameValue = 'let seriesNamevalue = window.baskreport.format.getFormatterString(JSON.parse(\''+JSON.stringify(variable)+'\'), params.seriesName)';
          }
          else if (variable.name=="name") {
            nameValue = 'let namevalue = window.baskreport.format.getFormatterString(JSON.parse(\''+JSON.stringify(variable)+'\'), params.name)';
          }
          else if (variable.name=="percent") {
            percentValue = 'let percentvalue = window.baskreport.format.getFormatterString(JSON.parse(\''+JSON.stringify(variable)+'\'), params.percent)';
          }
          else if (variable.name=="value") {
            if (value!='') value+="+' : '";
            
            keyValue = 'let keyvalue = '+params+';\n'+
            'let option = window.baskreport.chartOptions[\''+optionKey+'\'];\n'+
            'if (typeof('+params+'.seriesIndex)!=\'undefined\') {\n'+
            ' let series = option.series[params.seriesIndex];\n'+
            ' if (series.coordinateSystem && series.coordinateSystem==\'cartesian2d\'){\n'+
            '  if (Array.isArray(params.value)) {\n'+
            '   let yAxisIndex = 0;\n'+
            '   if (series.yAxisIndex) {\n'+
            '     yAxisIndex = series.yAxisIndex;\n'+
            '   }\n'+
            '   let yAxis = option.yAxis[yAxisIndex];\n'+
            '   keyvalue = window.baskreport.format.getFormatterString(JSON.parse(\''+JSON.stringify(variable)+'\'), (yAxis.type==\'category\')?params.value[0]:params.value[1]);\n'+
            '  } else {\n' +
            '     keyvalue = window.baskreport.format.getFormatterString(JSON.parse(\''+JSON.stringify(variable)+'\'), params.value);\n'+
            '  }\n'+
            ' }\n'+
            ' else if (series.coordinateSystem && series.coordinateSystem==\'polar\'){\n'+
            '   let radiusName = series.encode.radius;\n'+
            '   keyvalue = window.baskreport.format.getFormatterString(JSON.parse(\''+JSON.stringify(variable)+'\'), params.value[radiusName]);\n'+
            ' }\n'+
            ' else {\n'+
            '   keyvalue = window.baskreport.format.getFormatterString(JSON.parse(\''+JSON.stringify(variable)+'\'), params.value);\n'+
            ' }\n'+
            '}\n'+
            'else {\n'+
            '   keyvalue = window.baskreport.format.getFormatterString(JSON.parse(\''+JSON.stringify(variable)+'\'), '+params+');\n'+
            '}';
          }
          
      }
  });
  const str = 'function('+params+') { \r\n \t '+seriesNameValue+'\r\n\t ' + nameValue+'\r\n\t '+percentValue+'\r\n\t '+keyValue+'\r\n\t '+
  'if (seriesNamevalue.indexOf(\'numeral(\')>-1 || seriesNamevalue.indexOf(\'formatDate\')>-1) seriesNamevalue = eval(seriesNamevalue); '+'\r\n\t '+
  'if (namevalue.indexOf(\'numeral(\')>-1 || namevalue.indexOf(\'formatDate\')>-1) {namevalue = eval(namevalue);} '+'\r\n\t '+
  'if (percentvalue.indexOf(\'numeral(\')>-1 || percentvalue.indexOf(\'formatDate\')>-1) percentvalue = eval(percentvalue); '+'\r\n\t '+
  'if (keyvalue.indexOf(\'numeral(\')>-1 || keyvalue.indexOf(\'formatDate\')>-1) keyvalue = eval(keyvalue); '+'\r\n\t '+
  'let result = seriesNamevalue;'+'\r\n\t '+
  'if (result) { if (namevalue) { result=result+\' : \'+namevalue; } } else {result = namevalue;}'+'\r\n\t '+
  'if (result) { if (percentvalue) { result=result+\' : \'+percentvalue; }} else {result = percentvalue;}'+'\r\n\t '+
  'if (result) { if (keyvalue) { result=result+\' : \'+keyvalue; }} else {result = keyvalue;}'+'\r\n\t '+
  'return result;\r\n}';
  return str;
}

function genBaseFormatterFunction(optionKey:string, itemData:any){
  const values:any = {};
  itemData.templateVariables.forEach((variable:any)=>{
      if (variable.value) {
          values[variable.name] = 'let '+variable.name+'value= window.baskreport.format.getFormatterString(JSON.parse(\''+JSON.stringify(variable)+'\'), '+variable.name+');\n';
      }
  });
  let str = 'function('+itemData.parameterNames+') { \r\n \t ';
  for (var key in values){
      str += values[key]+'\r\n\t ';
      str += 'if ('+key+'value.indexOf(\'numeral(\')>-1 || '+key+'value.indexOf(\'formatDate\')>-1) '+key+'value = eval('+key+'value); '+'\r\n\t ';
  };
  str+= 'let result = \'\';'+'\r\n\t ';
  for (var key in values){
      str += 'if (result) { if ('+key+'value) { result=result+\' : \'+'+key+'value; } } else {result = '+key+'value;}'+'\r\n\t ';
  };
  str += 'return result;\r\n}';
  return str;
}

function converOptionFunctions(optionKey:string, attrName:string, obj:any) {
  try{
    // Handle Array
    if (obj instanceof Array) {
      for (let i = 0, len = obj.length; i < len; ++i) {
        if (obj[i] instanceof Object) {
          for (var attr in obj[i]) {
              if (obj[i].hasOwnProperty(attr)) converOptionFunctions(optionKey, attr, obj[i][attr]);
          }
        }
      }
    }
    // Handle Object
    else if (obj instanceof Object) {
        for (var attr in obj) {
          if (attr!='formatter') {
            if (obj.hasOwnProperty(attr)) converOptionFunctions(optionKey, attr, obj[attr]);
          } else {
            const functionExtra = obj[attr];
            if (functionExtra) {
              let value = functionExtra.value;
              if (!functionExtra.custom) {
                if (functionExtra.editor=='FormatterElement') {
                  value = genFormatterFunction(optionKey, functionExtra);
                  delete obj.formatter;
                }
                else if (functionExtra.editor=='BaseFormatterElement') {
                  value = genBaseFormatterFunction(optionKey, functionExtra);
                  delete obj.formatter;
                }
              }
              if (value) {
                try{
                  eval("obj['formatter'] = " + value);
                }catch(e){
                  console.log("optionKey:"+optionKey+",attrName:formatter");
                  console.log(value);
                  console.log(e);
                }
              }
            }
          }
        }
    }
    // Handle string function
    else if ("string" == typeof obj) {
        if (obj.indexOf("function") == 0) {
            eval("parent['"+attrName+"'] = " + obj);
        }
    }
  }catch(e) {
    console.log("optionKey:"+optionKey+",attrName:"+attrName);
    console.log(obj);
    console.log(e);
  }

};